/*
 * Copyright 2017 Zhihu Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.xiaoyu.media.matisse.internal.ui.adapter

import android.content.Context
import android.database.Cursor
import android.graphics.drawable.Drawable
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.CheckBox
import android.widget.ImageView
import android.widget.Toast

import com.xiaoyu.media.matisse.internal.entity.Album
import com.xiaoyu.media.matisse.internal.entity.IncapableCause
import com.xiaoyu.media.matisse.internal.entity.Item
import com.xiaoyu.media.matisse.internal.entity.SelectionSpec
import com.xiaoyu.media.matisse.internal.model.SelectedItemCollection
import com.xiaoyu.media.matisse.internal.ui.widget.CheckView
import com.xiaoyu.media.matisse.internal.ui.widget.MediaGrid
import com.xiaoyu.media.R

class AlbumMediaAdapter(context: Context, private val mSelectedCollection: SelectedItemCollection, private val mRecyclerView: RecyclerView) : RecyclerViewCursorAdapter<RecyclerView.ViewHolder>(null), MediaGrid.OnMediaGridClickListener {
    private val mPlaceholder: Drawable?
    private val mSelectionSpec: SelectionSpec
    private var mCheckStateListener: CheckStateListener? = null
    private var mOnMediaClickListener: OnMediaClickListener? = null
    private var mImageResize: Int = 0

    init {
        mSelectionSpec = SelectionSpec.instance

        val ta = context.theme.obtainStyledAttributes(intArrayOf(R.attr.item_placeholder))
        mPlaceholder = ta.getDrawable(0)
        ta.recycle()
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
        if (viewType == VIEW_TYPE_CAPTURE) {
            val view = LayoutInflater.from(parent.context).inflate(R.layout.matisse_photo_capture_item, parent, false)
            val holder = CaptureViewHolder(view)
            holder.itemView.setOnClickListener { v ->
                if (v.context is OnPhotoCapture) {
                    (v.context as OnPhotoCapture).capture()
                }
            }
            return holder
        } else if (viewType == VIEW_TYPE_MEDIA) {
            val v = LayoutInflater.from(parent.context).inflate(R.layout.matisse_media_grid_item, parent, false)
            return MediaViewHolder(v)
        }
        return CaptureViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.matisse_photo_capture_item, parent, false))
    }

    override fun onBindViewHolder(holder: RecyclerView.ViewHolder, cursor: Cursor) {
        if (holder is CaptureViewHolder) {

        } else if (holder is MediaViewHolder) {

            val item = Item.valueOf(cursor)
            mPlaceholder?.let {
                holder.mMediaGrid.preBindMedia(MediaGrid.PreBindInfo(
                        getImageResize(holder.mMediaGrid.context),
                        mPlaceholder,
                        mSelectionSpec.countable,
                        holder
                ))
            }
            item?.let {
                holder.mMediaGrid.bindMedia(item)
                holder.mMediaGrid.setOnMediaGridClickListener(this)
                setCheckStatus(item, holder.mMediaGrid)
            }
        }
    }

    private fun setCheckStatus(item: Item, mediaGrid: MediaGrid) {
        if (mSelectionSpec.isLongVideo(item)) {
            mediaGrid.setCheckEnabled(false)
            mediaGrid.setChecked(false)
            return
        }
        if (mSelectionSpec.countable) {
            val checkedNum = mSelectedCollection.checkedNumOf(item)
            if (checkedNum > 0) {
                mediaGrid.setCheckEnabled(true)
                mediaGrid.setCheckedNum(checkedNum)
            } else {
                if (mSelectedCollection.maxSelectableReached()) {
                    mediaGrid.setCheckEnabled(false)
                    mediaGrid.setCheckedNum(CheckView.UNCHECKED)
                } else {
                    mediaGrid.setCheckEnabled(true)
                    mediaGrid.setCheckedNum(checkedNum)
                }
            }
        } else {
            val selected = mSelectedCollection.isSelected(item)
            if (selected) {
                mediaGrid.setCheckEnabled(true)
                mediaGrid.setChecked(true)
            } else {
                if (mSelectedCollection.maxSelectableReached()) {
                    mediaGrid.setCheckEnabled(false)
                    mediaGrid.setChecked(false)
                } else {
                    mediaGrid.setCheckEnabled(true)
                    mediaGrid.setChecked(false)
                }
            }
        }
    }

    override fun onThumbnailClicked(thumbnail: ImageView?, item: Item?, holder: RecyclerView.ViewHolder) {
        if (SelectionSpec.instance.isLongVideo(item)) {
            Toast.makeText(thumbnail?.context, R.string.error_over_max_video_duration, Toast.LENGTH_SHORT).show()
            return
        }

        mOnMediaClickListener?.onMediaClick(null, item, holder.adapterPosition)
    }

    override fun onCheckViewClicked(checkView: CheckBox?, item: Item?, holder: RecyclerView.ViewHolder) {
        if (SelectionSpec.instance.isLongVideo(item)) {
            Toast.makeText(checkView?.context, R.string.error_over_max_video_duration, Toast.LENGTH_SHORT).show()
            return
        }

        if (mSelectionSpec.countable) {
            val checkedNum = item?.let { mSelectedCollection.checkedNumOf(it) }
            if (checkedNum == CheckView.UNCHECKED) {
                if (assertAddSelection(holder.itemView.context, item)) {
                    mSelectedCollection.add(item)
                    notifyCheckStateChanged()
                }
            } else {
                item?.let { mSelectedCollection.remove(it) }
                notifyCheckStateChanged()
            }
        } else {
            if (item?.let { mSelectedCollection.isSelected(it) } == true) {
                mSelectedCollection.remove(item)
                notifyCheckStateChanged()
            } else {
                if (item?.let { assertAddSelection(holder.itemView.context, it) } == true) {
                    mSelectedCollection.add(item)
                    notifyCheckStateChanged()
                }
            }
        }
    }

    private fun notifyCheckStateChanged() {
        notifyDataSetChanged()
        if (mCheckStateListener != null) {
            mCheckStateListener?.onUpdate()
        }
    }

    public override fun getItemViewType(position: Int, cursor: Cursor): Int {
        return if (Item.valueOf(cursor)?.isCapture == true) VIEW_TYPE_CAPTURE else VIEW_TYPE_MEDIA
    }

    private fun assertAddSelection(context: Context, item: Item): Boolean {
        val cause = mSelectedCollection.isAcceptable(item)
        IncapableCause.handleCause(context, cause)
        return cause == null
    }


    fun registerCheckStateListener(listener: CheckStateListener) {
        mCheckStateListener = listener
    }

    fun unregisterCheckStateListener() {
        mCheckStateListener = null
    }

    fun registerOnMediaClickListener(listener: OnMediaClickListener) {
        mOnMediaClickListener = listener
    }

    fun unregisterOnMediaClickListener() {
        mOnMediaClickListener = null
    }

    fun refreshSelection() {
        val layoutManager = mRecyclerView.layoutManager as GridLayoutManager?
        val first = layoutManager?.findFirstVisibleItemPosition() ?: 0
        val last = layoutManager?.findLastVisibleItemPosition() ?: 0
        if (first == -1 || last == -1) {
            return
        }
        val cursor = cursor
        for (i in first..last) {
            val holder = mRecyclerView.findViewHolderForAdapterPosition(first)
            if (holder is MediaViewHolder) {
                cursor?.let {
                    if (cursor.moveToPosition(i)) {
                        Item.valueOf(cursor)?.let { it1 -> setCheckStatus(it1, holder.mMediaGrid) }
                    }
                }
            }
        }
    }

    private fun getImageResize(context: Context): Int {
        if (mImageResize == 0) {
            val lm = mRecyclerView.layoutManager
            val spanCount = (lm as GridLayoutManager).spanCount
            val screenWidth = context.resources.displayMetrics.widthPixels
            val availableWidth = screenWidth - context.resources.getDimensionPixelSize(
                    R.dimen.media_grid_spacing) * (spanCount - 1)
            mImageResize = availableWidth / spanCount
            mImageResize = (mImageResize * mSelectionSpec.thumbnailScale).toInt()
        }
        return mImageResize
    }

    interface CheckStateListener {
        fun onUpdate()
    }

    interface OnMediaClickListener {
        fun onMediaClick(album: Album?, item: Item?, adapterPosition: Int)
    }

    interface OnPhotoCapture {
        fun capture()
    }

    private class MediaViewHolder internal constructor(itemView: View) : RecyclerView.ViewHolder(itemView) {

        internal val mMediaGrid: MediaGrid = itemView as MediaGrid
    }

    private class CaptureViewHolder internal constructor(itemView: View) : RecyclerView.ViewHolder(itemView) {

        private val mHint: ImageView = itemView.findViewById<View>(R.id.hint) as ImageView
    }

    companion object {

        private const val VIEW_TYPE_CAPTURE = 0x01
        private const val VIEW_TYPE_MEDIA = 0x02
    }
}
